home *** CD-ROM | disk | FTP | other *** search
- /* Kevo -- a prototype-based object-oriented language */
- /* (c) Antero Taivalsaari 1991-1993 */
- /* Some parts (c) Antero Taivalsaari 1986-1988 */
- /* kernel.c: Lowest-level internals */
-
- #include "global.h"
- #include "portGlobal.h"
-
- /*--------------------------------------------------------------------------*/
- /* Primitive stack operations */
-
- /*
- These definitions are the most primitive internals. They are
- not visible to the user, but they are convenient in other
- definitions.
- */
-
- /*
- To enable multitasking, stacks are allocated from the heap,
- which makes the following operations a bit more complicated.
- For safety, each stack is assumed to have an underflow area.
-
- Note that in the current implementation, stacks grow upwards
- so they can be resized flexibly at runtime.
- */
- /* Return the address of data stack top */
- int* dataStackBottom()
- {
- /* Access the data stack field in the task data area */
- OBJECT* stack = (*up)->dataStack;
- /* Return the bottom address, taking into account the underflow area */
- return((int*)((int*)stack->mfa + DATAOFFSET + UNDERFLOWRESERVE - 1));
- }
-
-
- int** returnStackBottom()
- {
- /* Access the return stack field in the task data area */
- OBJECT* stack = (*up)->returnStack;
- /* Return the bottom address, taking into account the underflow area */
- return((int**)((int*)stack->mfa + DATAOFFSET + UNDERFLOWRESERVE - 1));
- }
-
-
- int** contextStackBottom()
- {
- /* Access the context stack field in the task data area */
- OBJECT* stack = (*up)->contextStack;
- /* Return the bottom address, taking into account the underflow area */
- return((int**)((int*)stack->mfa + DATAOFFSET + UNDERFLOWRESERVE - 1));
- }
-
-
- void resetData()
- {
- dataSp = dataStackBottom();
- }
-
-
- void resetReturn()
- {
- returnSp = returnStackBottom();
- }
-
-
- void resetContext()
- {
- contextSp = contextStackBottom();
- }
-
-
- /* initStacks(): initialize execution stacks */
- void initStacks()
- {
- resetData();
- resetReturn();
- resetContext();
- }
-
-
- /*---------------------------------------------------------------------------*/
- /* Inner interpreters/multitaskers */
-
- /*
- These are not visible to the user either. They, however, constitute the
- heart of the whole Kevo system, and the runtime efficiency of the system
- depends fundamentally on them.
- */
-
- /* This is the heart of the multitasker: task switcher */
- /* Note that task will be switched only if multitasking is allowed */
- void yield()
- {
- /* Event loop must be executed if enough time has passed */
- /* yyy warning: this line of code is non-portable */
-
- if (TickCount() >= nextTime) EventLoop();
-
- /* If multitasking, switch task */
- if (multitasking) {
- /* This code is the equivalent of 'yieldTo((*up)->nextInRobin)' */
- /* see 'tasks.c'. For efficiency, the code has been "inlined" */
-
- nPushReturn(3); /* Macro: push three items to return stack */
- thirdReturn = (int*)contextSp;
- secondReturn = (int*)dataSp;
- topReturn = (int*)ip;
- (*up)->rpStore = returnSp;
-
- up = (*up)->nextInRobin; /* Task switch!!! */
-
- returnSp = (*up)->rpStore;
- ip = (int**)topReturn;
- dataSp = secondReturn;
- contextSp = (int**)thirdReturn;
- nPopReturn(3); /* Macro: pop three items from return stack */
- }
-
- /* Load new time slice */
- slice = (*up)->priority;
- }
-
-
- /* This is the big kabloona: preemptive inner interpreter/multitasker */
-
- /*
- Remember: due to having to keep track of the pointer to the last
- object handle ('op'), it is important that task switches cannot occur
- when going from a high-level operation to a primitive.
-
- Therefore, in the current implementation 'yield()' can be called
- only right after executing a primitive.
- */
-
- void preemptiveInterpreter()
- {
- register OBJECT* object;
-
- fprintf(confile, "Kevo running.\n");
-
- /* Store environment so that we can return here later */
- (void)setjmp(p_inner);
-
- mtaskMode = PREEMPTIVE;
- traceMode = NOTRACE;
- supervisor = FALSE;
-
- slice = (*up)->priority;
- while(TRUE) {
-
- /* High-level word (size field <> zero)? */
- if ((object = (OBJECT*)*ip++)->sfa) {
- pushReturn((int*)ip);
- ip = (int**)(op = object)->mfa;
- }
- /* else invoke primitive */
- else {
- ((void (*)())object->mfa)();
-
- /* Decrement time slice */
- if (--slice <= 0) yield();
- }
- }
- }
-
-
- /* This is another kabloona: cooperative inner interpreter. */
- /* This is about 20-30% faster than the preemptive one, because no slice */
- /* counter is needed, but on the other hand operations like loops block */
- /* the execution of other tasks (requires cooperation from all the tasks). */
-
- /* In many cases preemptive interpreter may seem faster to the user, */
- /* because cooperative multitasking requires that all tasks are relatively */
- /* equal in their demand for computing power. */
-
- /* Note: most I/O commands in Kevo contain a call to 'yield()', so as long */
- /* as a task does I/O, it is automatically guaranteed to cooperate with */
- /* other tasks. */
-
- void cooperativeInterpreter()
- {
- register OBJECT* object;
-
- /* Store environment so that we can return here later */
- (void)setjmp(c_inner);
-
- mtaskMode = COOPERATIVE;
- traceMode = NOTRACE;
- supervisor = FALSE;
-
- while(TRUE) {
-
- /* High-level word (size field <> zero)? */
- if ((object = (OBJECT*)*ip++)->sfa) {
- pushReturn((int*)ip);
- ip = (int**)(op = object)->mfa;
- }
- /* else invoke primitive */
- else ((void (*)())object->mfa)();
- }
- }
-
-
- /* This version of longjmp automatically restores the correct environment */
-
- void ownLongJmp()
- {
- if (mtaskMode == PREEMPTIVE) longjmp(p_inner, TRUE);
- else longjmp(c_inner, TRUE);
- }
-
-
- /* This execution operation is needed in many other primitive definitions */
- /* Executes a high-level or primitive object */
- void execute(object)
- OBJECT* object;
- {
- if (object->sfa) {
- /* Execute a high-level definition */
- pushReturn((int*)ip);
- ip = (int**)(op = object)->mfa;
- /* Due to 'op', task should never be switched right after */
- /* executing a high-level operation */
- slice++;
- }
- /* Execute primitive */
- else ((void (*)())object->mfa)();
- }
-
-